home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint96sb.zoo / src / bios.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-18  |  17.4 KB  |  767 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * BIOS replacement routines
  7.  */
  8.  
  9. #include "mint.h"
  10.  
  11. #define UNDEF 0        /* should match definition in tty.c */
  12.  
  13. /* some key definitions */
  14. #define CTRLALT 0xc
  15. #define DEL 0x53    /* scan code of delete key */
  16. #define UNDO 0x61    /* scan code of undo key */
  17.  
  18. /* BIOS device definitions */
  19. #define CONSDEV 2
  20. #define AUXDEV 1
  21.  
  22. /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
  23. #define MAX_BHANDLE    4
  24.  
  25. /* BIOS redirection maps */
  26. const short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
  27. const short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
  28.  
  29. /* tty structures for the BIOS devices -- see biosfs.c */
  30. extern struct tty con_tty, aux_tty, midi_tty;
  31.  
  32. extern int tosvers;    /* from main.c */
  33. char *kbshft;        /* set in main.c */
  34.  
  35. /* some BIOS vectors; note that the routines at these vectors may do nasty
  36.  * things to registers!
  37.  */
  38.  
  39. #define RWABS *((long *)0x476L)
  40. #define MEDIACH *((long *)0x47eL)
  41. #define GETBPB *((long *)0x472L)
  42.  
  43. /* these are supposed to be tables holding the addresses of the
  44.  * first 8 BconXXX functions, but in fact only the first 5 are
  45.  * placed here (and device 5 only has Bconout implemented; 
  46.  * we don't use that device (raw console) anyway).
  47.  */
  48.  
  49. #define xconstat ((long *)0x51eL)
  50. #define xconin     ((long *)0x53eL)
  51. #define xcostat ((long *)0x55eL)
  52. #define xconout    ((long *)0x57eL)
  53.  
  54. #define BCOSTAT(dev) \
  55.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  56.        (int)callout1(xcostat[dev], dev) : Bcostat(dev))
  57. #define BCONOUT(dev, c) \
  58.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  59.        callout2(xconout[dev], dev, c) : Bconout(dev, c))
  60. #define BCONSTAT(dev) \
  61.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  62.        (int)callout1(xconstat[dev], dev) : Bconstat(dev))
  63. #define BCONIN(dev) \
  64.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  65.        callout1(xconin[dev], dev) : Bconin(dev))
  66.  
  67. /* variables for monitoring the keyboard */
  68. IOREC_T    *keyrec;        /* keyboard i/o record pointer */
  69. short    kintr = 0;        /* keyboard interrupt pending (see intr.s) */
  70.  
  71. /* Getmpb is not allowed under MiNT */
  72.  
  73. long ARGS_ON_STACK
  74. getmpb(ptr)
  75.     void *ptr;
  76. {
  77.     UNUSED(ptr);
  78.  
  79.     DEBUG(("failed call to Getmpb"));
  80.     return -1;
  81. }
  82.  
  83.  
  84. /*
  85.  * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
  86.  * to get the physical devices, go through u:\dev\
  87.  *
  88.  * A note on translation: all of the bco[n]XXX functions have a "u"
  89.  * variant that is actually what the user calls. For example,
  90.  * ubconstat is the function that gets control after the user does
  91.  * a Bconstat. It figures out what device or file handle is
  92.  * appropriate. Typically, it will be a biosfs file handle; a
  93.  * request is sent to biosfs, and biosfs in turn figures out
  94.  * the "real" device and calls bconstat.
  95.  */
  96.  
  97. /*
  98.  * WARNING: syscall.spp assumes that ubconstat never blocks.
  99.  */
  100. long ARGS_ON_STACK
  101. ubconstat(dev)
  102. int dev;
  103. {
  104.     if (dev < MAX_BHANDLE) {
  105.         FILEPTR *f = curproc->handle[binput[dev]];
  106.         return file_instat(f) ? -1 : 0;
  107.     }
  108.     else
  109.         return bconstat(dev);
  110. }
  111.  
  112. long
  113. bconstat(dev)
  114. int dev;
  115. {
  116.     if (dev == CONSDEV) {
  117.         if (checkkeys()) return 0;
  118.         return (keyrec->head != keyrec->tail) ? -1 : 0;
  119.     }
  120.     if (dev == AUXDEV && has_bconmap)
  121.         dev = curproc->bconmap;
  122.  
  123.     return BCONSTAT(dev);
  124. }
  125.  
  126. /* bconin: input a character */
  127. /*
  128.  * WARNING: syscall.spp assumes that ubconin never
  129.  * blocks if ubconstat returns non-zero.
  130.  */
  131. long ARGS_ON_STACK
  132. ubconin(dev)
  133. int dev;
  134. {
  135.     if (dev < MAX_BHANDLE) {
  136.         FILEPTR *f = curproc->handle[binput[dev]];
  137.         return file_getchar(f, RAW);
  138.     }
  139.     else
  140.         return bconin(dev);
  141. }
  142.  
  143. long
  144. bconin(dev)
  145. int dev;
  146. {
  147.     IOREC_T *k;
  148.     long r;
  149.     short h;
  150.  
  151.     if (dev == CONSDEV) {
  152.         k = keyrec;
  153. again:
  154.         while (k->tail == k->head) {
  155.             yield();
  156.         }
  157.  
  158.         if (checkkeys()) goto again;
  159.  
  160.         h = k->head + 4;
  161.         if (h >= k->buflen)
  162.             h = 0;
  163.         r = *((long *)(k->bufaddr + h));
  164.         k->head = h;
  165.         return r;
  166.     }
  167.     else {
  168.         if (dev == AUXDEV && has_bconmap)
  169.             dev = curproc->bconmap;
  170.  
  171.         if (dev > 0) {
  172.             while (!BCONSTAT(dev)) {
  173.                 yield();
  174.             }
  175.         }
  176.     }
  177.  
  178.     r = BCONIN(dev);
  179.  
  180.     return r;
  181. }
  182.  
  183. /* bconout: output a character.
  184.  * returns 0 for failure, nonzero for success
  185.  */
  186.  
  187. long ARGS_ON_STACK
  188. ubconout(dev, c)
  189. int dev, c;
  190. {
  191.     FILEPTR *f;
  192.     char outp;
  193.  
  194.     if (dev < MAX_BHANDLE) {
  195.         f = curproc->handle[boutput[dev]];
  196.         if (!f) return 0;
  197.         if (is_terminal(f)) {
  198.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  199.         }
  200.         outp = c;
  201.         return (*f->dev->write)(f, &outp, 1L);
  202.     }
  203.     else if (dev == 5) {
  204.         c &= 0x00ff;
  205.         f = curproc->handle[-1];
  206.         if (!f) return 0;
  207.         if (is_terminal(f)) {
  208.             if (c < ' ') {
  209.             /* MW hack for quoted characters */
  210.                 tty_putchar(f, (long)'\033', RAW);
  211.                 tty_putchar(f, (long)'Q', RAW);
  212.             }
  213.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  214.         }
  215.     /* note: we're assuming sizeof(int) == 2 here! */
  216.         outp = c;
  217.         return (*f->dev->write)(f, &outp, 1L);
  218.     } else
  219.         return bconout(dev, c);
  220. }
  221.  
  222. long
  223. bconout(dev, c)
  224. int dev,c;
  225. {
  226.     int statdev;
  227.     long endtime;
  228.     extern long searchtime;    /* in dosdir.c; updated once per second */
  229.  
  230.     if (dev == AUXDEV && has_bconmap) {
  231.         dev = curproc->bconmap;
  232.     }
  233.  
  234. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  235.     if (dev == 3) {        /* MIDI */
  236.         statdev = 4;
  237.     } else if (dev == 4) {
  238.         statdev = 3;
  239.     } else
  240.         statdev = dev;
  241.  
  242. /* provide a 10 second time out */
  243.     if (!BCOSTAT(statdev)) {
  244.         endtime = searchtime + 10;
  245.         do {
  246.             yield();
  247.         } while (!BCOSTAT(statdev) && searchtime < endtime);
  248.         if ( searchtime >= endtime) return 0;
  249.     }
  250.  
  251. /* special case: many text accelerators return a bad value from
  252.  * Bconout, so we ignore the returned value for the console
  253.  */
  254.     if (dev != CONSDEV) {
  255. /* NOTE: if your compiler complains about the next line, then Bconout is
  256.  * improperly declared in your osbind.h header file. it should be returning
  257.  * a long value; some libraries incorrectly have Bconout returning void
  258.  * (or cast the returned value to void)
  259.  */
  260.         return BCONOUT(dev,c);
  261.     } else {
  262.         (void)BCONOUT(dev, c);
  263.         return 1;
  264.     }
  265. }
  266.  
  267. /* rwabs: various disk stuff */
  268.  
  269. /* BUG: Rwabs should respect Dlock */
  270.  
  271. long ARGS_ON_STACK
  272. rwabs(rwflag, buffer, number, recno, dev, lrecno)
  273. int rwflag, number, recno, dev;
  274. void *buffer;
  275. long lrecno;
  276. {
  277.     long r;
  278.     extern PROC *dlockproc[];    /* in dosdir.c */
  279.  
  280.     if (dev >= 0 && dev < NUM_DRIVES && dlockproc[dev]) {
  281.         if (dlockproc[dev] != curproc) {
  282.             DEBUG(("Rwabs: device %c is locked", dev+'A'));
  283.             return ELOCKED;
  284.         }
  285.     }
  286.  
  287. /* Note that some (most?) Rwabs device drivers don't bother saving
  288.  * registers, whereas our compiler expects politeness. So we go
  289.  * via callout(), which will save registers for us.
  290.  */
  291.     r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  292.     return r;
  293. }
  294.  
  295. /* setexc: set exception vector */
  296.  
  297. long ARGS_ON_STACK
  298. setexc(number, vector)
  299. int number;
  300. long vector;
  301. {
  302.     long *place;
  303.     long old;
  304.     extern long save_dos, save_bios, save_xbios;    /* in main.c */
  305.  
  306.     TRACE(("Setexc %d, %lx", number, vector));
  307.     place = (long *)(((long)number) << 2);
  308.     if (number == 0x21)                /* trap_1 */
  309.         old = save_dos;
  310.     else if (number == 0x2d)            /* trap_13 */
  311.         old = save_bios;
  312.     else if (number == 0x2e)            /* trap_14 */
  313.         old = save_xbios;
  314.     else if (number == 0x101)
  315.         old = (long)curproc->criticerr;        /* critical error vector */
  316.     else if (number == 0x102)
  317.         old = curproc->ctxt[SYSCALL].term_vec;    /* GEMDOS term vector */
  318.     else
  319.         old = *place;
  320.  
  321.     if (vector > 0) {
  322.         if (number == 0x21)
  323.             save_dos = vector;
  324.         else if (number == 0x2d)
  325.             save_bios = vector;
  326.         else if (number == 0x2e)
  327.             save_xbios = vector;
  328.         else if (number == 0x102)
  329.             curproc->ctxt[SYSCALL].term_vec = vector;
  330.         else if (number == 0x101) {
  331.             long mintcerr;
  332.  
  333.         /*
  334.          * problem: lots of TSR's look for the Setexc(0x101,...)
  335.           * that the AES does at startup time; so we have
  336.          * to pass it along.
  337.          */
  338.             mintcerr = (long) Setexc(0x101, (void *)vector);
  339.             curproc->criticerr = (long ARGS_ON_STACK (*) P_((long))) *place;
  340.             *place = mintcerr;
  341.         }
  342.         else {
  343.         /* We would do just *place = vector except that
  344.          * someone else might be intercepting Setexc looking
  345.          * for something in particular...
  346.          */
  347.             old = (long) Setexc(number, (void *)vector);
  348.         }
  349.     }
  350.     return old;
  351. }
  352.  
  353. /* tickcal: return milliseconds per system clock tick */
  354.  
  355. long ARGS_ON_STACK
  356. tickcal()
  357. {
  358.     return (long) (*( (unsigned *) 0x0442L ));
  359. }
  360.  
  361. /* getbpb: get BIOS parameter block */
  362.  
  363. long ARGS_ON_STACK
  364. getbpb(dev)
  365. int dev;
  366. {
  367.     long r;
  368.  
  369. /* we can't trust the Getbpb routine to accurately save all registers,
  370.  * so we do it ourselves
  371.  */
  372.     r = callout(GETBPB, dev);
  373. /* 
  374.  * There is a bug in the  TOS  disk handling routines (well several actually).
  375.  * If the directory size of Getbpb() is returned as zero then the drive 'dies'
  376.  * and wont read any new disks even with the 'ESC' enforced disk change . This
  377.  * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
  378.  * changes the dir size to '1' if it is zero . It may make some non-TOS disks
  379.  * look a bit weird but that's better than killing the drive .
  380.  */
  381.     if (r) {
  382.         if ( ((short *)r)[3] == 0)    /* 0 directory size? */
  383.             ((short *)r)[3] = 1;
  384.     }
  385.     return r;
  386. }
  387.  
  388. /* bcostat: return output device status */
  389.  
  390. /* WARNING: syscall.spp assumes that ubcostat never
  391.  * blocks
  392.  */
  393. long ARGS_ON_STACK
  394. ubcostat(dev)
  395. int dev;
  396. {
  397.     FILEPTR *f;
  398.  
  399. /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
  400.     if (dev == 4) {        /* really the MIDI port */
  401.         f = curproc->handle[boutput[3]];
  402.         return file_outstat(f) ? -1 : 0;
  403.     }
  404.     if (dev == 3)
  405.         return BCOSTAT(dev);
  406.  
  407.     if (dev < MAX_BHANDLE) {
  408.         f = curproc->handle[boutput[dev]];
  409.         return file_outstat(f) ? -1 : 0;
  410.     } else
  411.         return bcostat(dev);
  412. }
  413.  
  414. long
  415. bcostat(dev)
  416. int dev;
  417. {
  418.  
  419.     if (dev == CONSDEV) {
  420.         return -1;
  421.     }
  422.     else if (dev == AUXDEV && has_bconmap) {
  423.         dev = curproc->bconmap;
  424.     }
  425. /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
  426.  * correctly
  427.  */
  428.     else if (dev == 3) dev = 4;
  429.     else if (dev == 4) dev = 3;
  430.  
  431.     return BCOSTAT(dev);
  432. }
  433.  
  434. /* mediach: check for media change */
  435.  
  436. long ARGS_ON_STACK
  437. mediach(dev)
  438. int dev;
  439. {
  440.     long r;
  441.  
  442.     r = callout(MEDIACH, dev);
  443.     return r;
  444. }
  445.  
  446. /* drvmap: return drives connected to system */
  447.  
  448. long ARGS_ON_STACK
  449. drvmap()
  450. {
  451.     return *( (long *)0x4c2L );
  452. }
  453.  
  454. /* kbshift: return (and possibly change) keyboard shift key status */
  455. /* WARNING: syscall.spp assumes that kbshift never blocks, and never
  456.  * calls any underlying TOS functions
  457.  */
  458. long ARGS_ON_STACK
  459. kbshift(mode)
  460. int mode;
  461. {
  462.     int oldshft;
  463.  
  464.     oldshft = *((unsigned char *)kbshft);
  465.     if (mode >= 0)
  466.         *kbshft = mode;
  467.     return oldshft;
  468. }
  469.  
  470.  
  471. /* special Bconout buffering code:
  472.  * Because system call overhead is so high, programs that do output
  473.  * with Bconout suffer in performance. To compensate for this,
  474.  * Bconout is special-cased in syscall.s, and if possible characters
  475.  * are placed in the 256 byte bconbuf buffer. This buffer is flushed
  476.  * when any system call other than Bconout happens, or when a context
  477.  * switch occurs.
  478.  */
  479.  
  480. short bconbsiz;            /* number of characters in buffer */
  481. unsigned char bconbuf[256];    /* buffer contents */
  482. short bconbdev;            /* BIOS device for which the buffer is valid */
  483.                 /* (-1 means no buffering is active) */
  484.  
  485. /*
  486.  * flush pending BIOS output. Return 0 if some bytes were not successfully
  487.  * written, non-zero otherwise (just like bconout)
  488.  */
  489.  
  490. long ARGS_ON_STACK
  491. bflush()        /* flush bios output */
  492. {
  493.     long ret, bsiz;
  494.     unsigned char *s;
  495.     FILEPTR *f;
  496.     short dev;
  497.     short statdev;
  498.     long lbconbuf[256];
  499.  
  500.     if ((dev = bconbdev) < 0) return 0;
  501.  
  502. /*
  503.  * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
  504.  * This is necessary because if two or more programs try to do
  505.  * buffered BIOS output at the same time, they can get seriously
  506.  * mixed up. We unlock by setting bconbdev to 0.
  507.  *
  508.  * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
  509.  * order to see if we need to do a bflush; if one is already in
  510.  * progress, it's pointless to do this, so we save a bit of
  511.  * time by setting bconbsiz to 0 here.
  512.  */
  513.     bconbdev = -1;
  514.     bsiz = bconbsiz;
  515.     if (bsiz == 0) return 0;
  516.     bconbsiz = 0;
  517.  
  518. /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
  519.     if (dev < MAX_BHANDLE || dev == 5) {
  520.         if (dev == 5)
  521.             f = curproc->handle[-1];
  522.         else
  523.             f = curproc->handle[boutput[dev]];
  524.  
  525.         if (!f) {
  526.             bconbdev = 0;
  527.             return 0;
  528.         }
  529.         if (is_terminal(f)) {
  530.             s = bconbuf;
  531.             if (dev == 5) {
  532.                 while (bsiz-- > 0) {
  533.                 if (*s < ' ') {
  534.             /* use ESC-Q to quote control character */
  535.                     (void)tty_putchar(f, (long)'\033',
  536.                                 RAW);
  537.                     (void)tty_putchar(f, (long)'Q',
  538.                                 RAW);
  539.                 }
  540.                 (void) tty_putchar(f, (long)*s++, RAW);
  541.                 }
  542.             } else {
  543. #if 1
  544.                 long *where, nbytes;
  545.  
  546. /* the tty_putchar should set up terminal modes correctly */
  547.                 (void) tty_putchar(f, (long)*s++, RAW);
  548.                 where = lbconbuf;
  549.                 nbytes = 0;
  550.                 while (--bsiz > 0) {
  551.                 *where++ = *s++; nbytes+=4;
  552.                 }
  553.                 if (nbytes)
  554.                 (*f->dev->write)(f, (char *)lbconbuf, nbytes);
  555. #else
  556.                 while (bsiz-- > 0) {
  557.                 (void) tty_putchar(f, (long)*s++, RAW);
  558.                 }
  559. #endif
  560.             }
  561.             ret = -1;
  562.         } else {
  563.             ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
  564.         }
  565.         bconbdev = 0;
  566.         return ret;
  567.     }
  568.  
  569. /* Otherwise, we have a real BIOS device */
  570.  
  571.     if (dev == AUXDEV && has_bconmap) {
  572.         dev = curproc->bconmap;
  573.         statdev = dev;
  574.     }
  575. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  576.     else if (dev == 3) {        /* MIDI */
  577.         statdev = 4;
  578.     } else if (dev == 4) {
  579.         statdev = 3;
  580.     } else
  581.         statdev = dev;
  582.         
  583.     s = bconbuf;
  584.     while (bsiz-- > 0) {
  585.         while (!BCOSTAT(statdev)) yield();
  586.         (void)BCONOUT(dev,*s);
  587.         s++;
  588.     }
  589.     bconbdev = 0;
  590.     return 1L;
  591. }
  592.  
  593. /* initialize bios table */
  594.  
  595. #define BIOS_MAX 0x20
  596.  
  597. Func bios_tab[BIOS_MAX] = {
  598.     getmpb,
  599.     ubconstat,
  600.     ubconin,
  601.     ubconout,
  602.  
  603.     rwabs,
  604.     setexc,
  605.     tickcal,
  606.     getbpb,
  607.  
  608.     ubcostat,
  609.     mediach,
  610.     drvmap,
  611.     kbshift,
  612.  
  613.     0, 0, 0, 0,
  614.     0, 0, 0, 0, 0, 0, 0, 0,
  615.     0, 0, 0, 0, 0, 0, 0, 0
  616. };
  617.  
  618. short bios_max = BIOS_MAX;
  619.  
  620. /*
  621.  * BIOS initialization routine: gets keyboard buffer pointers, for the
  622.  * interrupt routine below
  623.  */
  624.  
  625. void
  626. init_bios()
  627. {
  628.     keyrec = (IOREC_T *)Iorec(1);
  629. }
  630.  
  631. /*
  632.  * do_bconin: try to do a bconin function quickly, without
  633.  * blocking. If we can't do it without blocking, we return
  634.  * 0x0123dead and the calling trap #13 code falls through
  635.  * to the normal bconin stuff. We can't block here because
  636.  * the trap #13 code hasn't yet saved registers or other
  637.  * context bits, so sleep() wouldn't work properly.
  638.  */
  639.  
  640. #define WOULDBLOCK 0x0123deadL
  641.  
  642. /* WARNING: syscall.spp assumes that do_bconin never blocks */
  643.  
  644. long ARGS_ON_STACK
  645. do_bconin(dev)
  646.     int dev;
  647. {
  648.     FILEPTR *f;
  649.     long r;
  650.     unsigned char c;
  651.  
  652.     if (dev < MAX_BHANDLE) {
  653.         f = curproc->handle[binput[dev]];
  654.         if (!f) return 0;
  655.         r = 0;
  656.         (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  657.         if (!r) return WOULDBLOCK;    /* data not ready */
  658.         if (is_terminal(f))
  659.             r = tty_getchar(f, RAW);
  660.         else {
  661.             r = (*f->dev->read)(f, (char *)&c, 1L);
  662.             r = (r == 1) ? c : MiNTEOF;
  663.         }
  664.     } else {
  665.         if (!bconstat(dev))
  666.             r = WOULDBLOCK;
  667.         else
  668.             r = bconin(dev);
  669.     }
  670.     return r;
  671. }
  672.  
  673. /*
  674.  * routine for checking keyboard (called by sleep() on any context
  675.  * switch where a keyboard event occured). returns 1 if a special
  676.  * control character was eaten, 0 if not
  677.  */
  678.  
  679. int
  680. checkkeys()
  681. {
  682.     char scan, ch;
  683.     short shift;
  684.     int sig, ret;
  685.     struct tty *tty = &con_tty;
  686.     extern char mshift;        /* for mouse -- see biosfs.c */
  687.     static short oldktail = 0;
  688.  
  689.     ret = 0;
  690.     mshift = kbshift(-1);
  691.     while (oldktail != keyrec->tail) {
  692.  
  693. /* BUG: we really should check the shift status _at the time the key was
  694.  * pressed_, not now!
  695.  */
  696.         sig = 0;
  697.         shift = mshift;
  698.         oldktail += 4;
  699.         if (oldktail >= keyrec->buflen)
  700.             oldktail = 0;
  701.  
  702.         scan = (keyrec->bufaddr + oldktail)[1];
  703. /* function key?? */
  704.         if ( (scan >= 0x3b && scan <= 0x44) ||
  705.              (scan >= 0x54 && scan <= 0x5d) ||
  706.              scan == DEL || scan == UNDO) {
  707.             if ( (shift & CTRLALT) == CTRLALT ) {
  708.                 oldktail = keyrec->head = keyrec->tail;
  709.                 do_func_key(scan);
  710.                 /* do_func_key may have read some keys */
  711.                 oldktail = keyrec->head;
  712.                 mshift = kbshift (-1);
  713.                 ret = 1;
  714.                 continue;
  715.             }
  716.         }
  717.  
  718. /* check for special control keys, etc. */
  719. /* BUG: this doesn't exactly match TOS' behavior, particularly for
  720.  * ^S/^Q
  721.  */
  722.         if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
  723.             ch = (keyrec->bufaddr + keyrec->tail)[3];
  724.             if (ch == UNDEF)
  725.                 ;    /* do nothing */
  726.             else if (ch == tty->tc.t_intrc)
  727.                 sig = SIGINT;
  728.             else if (ch == tty->tc.t_quitc)
  729.                 sig = SIGQUIT;
  730.             else if (ch == tty->ltc.t_suspc)
  731.                 sig = SIGTSTP;
  732.             else if (ch == tty->tc.t_stopc) {
  733.                 tty->state |= TS_HOLD;
  734.                 ret = 1;
  735.                 keyrec->head = oldktail;
  736.                 continue;
  737.             }
  738.             else if (ch == tty->tc.t_startc) {
  739.                 tty->state &= ~TS_HOLD;
  740.                 ret = 1;
  741.                 keyrec->head = oldktail;
  742.                 continue;
  743.             }
  744.             if (sig) {
  745.                 tty->state &= ~TS_HOLD;
  746.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  747.                     oldktail = keyrec->head = keyrec->tail;
  748.                 killgroup(tty->pgrp, sig);
  749.                 ret = 1;
  750.             }
  751.             else if (tty->state & TS_HOLD) {
  752.                 keyrec->head = oldktail;
  753.                 ret = 1;
  754.             }
  755.         }
  756.  
  757.     }
  758.  
  759. /* has someone done select() on the keyboard?? */
  760.     if (tty->rsel && keyrec->head != keyrec->tail)
  761.         wakeselect(tty->rsel);
  762.  
  763.     return ret;
  764. }
  765.  
  766. /* do_func_key moved to debug.c */
  767.